/*
 * Map.h
 *
 *  Created on: 20/10/2009
 *      Author: marcos
 */

#ifndef MAP_H_
#define MAP_H_

#include "Road.h"
#include "Route.h"
#include "MapLocation.h"

#include "exceptions/RoadNotFoundException.h"

#include "util/exceptions/ElementNotFoundException.h"
#include "util/LinkedList.h"
#include "util/logger/Logger.h"
#include "core/Graph.h"
#include "core/path/DijkstraShortestPath.h"
#include "core/path/TimeCost.h"
#include "core/path/DistanceCost.h"
#include "core/exceptions/DuplicateElementException.h"
#include <string>

using namespace std;
enum RouteOptimize {
	Time, Distance
};

class Map {
public:
	Map();
	virtual ~Map();
	/*
	 * Metodo para agregar un objeto mapa
	 */
	virtual MapLocation* addLocation(string id, string edgeId, int height,
			MapLocationType type)
	throw (DuplicateElementException);

	virtual void addIntersection(string id, double position_x = 0.0, double position_y = 0.0)
	throw (DuplicateElementException);

	/*
	 * Metodo para agregar un camino. Devuelve DuplicateElementException en caso de ya existir
	 * el camino o ElementNotFoundException en caso de no existir alguno del los extremos del camino.
	 */
	virtual Road* addRoad(string id, string roadName, string origin,
			string destination, double length, double maxSpeed,
			RoadType roadType, int minHeight, int maxHeight)
	throw (DuplicateElementException, util::ElementNotFoundException);

	virtual Route* route(string originRoadName, int originHeight,
			string destinationRoadName, int destinationHeight, RouteOptimize optimizationStrategy)
	throw(RoadNotFoundException, OutOfReachException);

	virtual util::LinkedList<RoadSegment*>* getAllSegments();
	virtual util::LinkedList<MapLocation*>* getMapLocations() { return &this->mapLocations; };
	double getFartherNorth() { return this->fartherNorth; }
	double getFartherSouth() { return this->fartherSouth; }
	double getFartherWest() { return this->fartherWest; }
	double getFartherEast() { return this->fartherEast; }

	/* Esto est� expuesto �nicamente para backward compatibility con el primer main */
	virtual Graph* getGraph() { return &this->graph; }
protected:
	Road* getRoad(string roadName) throw(RoadNotFoundException);
	Road* getOrBuildRoad(string roadName, RoadType roadType);
	Vertex* splitOutgoingEdges(util::LinkedList<RoadSegment*>* segments, int height);
	Vertex* splitIncomingEdges(util::LinkedList<RoadSegment*>* segments, int height);
	void splitFrom(Vertex* adHocVertex, util::LinkedList<Edge*>* edges, double percentage);
	void splitTo(Vertex* adHocVertex, util::LinkedList<Edge*>* edges, double percentage);
	/* Busca entre todos los RoadSegments el que tenga el id recibido por par�metro */
	RoadSegment* getSegmentContainingEdge(string edgeId);
	/* Devuelve el solver a utilizar para la estrategia elegida */
	path::DijkstraShortestPath* solver(RouteOptimize optimizationStrategy);
	/* Devuelve el logger */
	util::Logger* logger();
	virtual void updateHorizontalAxis(double x, bool firstTime);
	virtual void updateVerticalAxis(double y, bool firstTime);
private:
	util::LinkedList<MapLocation*> mapLocations;
	util::LinkedList<Road*> roads;
	path::DijkstraShortestPath timeSolver;
	path::DijkstraShortestPath distanceSolver;
	Graph graph;
	double fartherNorth;
	double fartherSouth;
	double fartherWest;
	double fartherEast;
};

#endif /* MAP_H_ */
